(ns win.com
  (:require util.loader) ; must use this to get DLL path set correctly
  (:use [util.utils :only [group2]])
  (:import [com.jacob.activeX ActiveXComponent]
           [com.jacob.com Dispatch Variant]))


(defn variant [v]
  (Variant. v))

(defn variant-to [v]
  (condp = (.getvt v)
    Variant/VariantString   (.getString v)
    Variant/VariantInt      (.getInt v)
    Variant/VariantEmpty    nil
    Variant/VariantNull     nil
    Variant/VariantShort    (.getShort v)
    Variant/VariantInt      (.getInt v)
    Variant/VariantFloat    (.getFloat v)
    Variant/VariantDouble   (.getDouble v)
    Variant/VariantCurrency (.getCurrency v)
    Variant/VariantDate     (.getDate v)
    Variant/VariantString   (.getString v)
    Variant/VariantDispatch (.getDispatch v)
    Variant/VariantError    (.getError v)
    Variant/VariantBoolean  (.getBoolean v)
    Variant/VariantVariant  (.getVariant v)
    Variant/VariantObject   (.getObject v)
    Variant/VariantDecimal  (.getDecimal v)
    Variant/VariantByte     (.getByte v)))


(defn dispatch-on [x properties]
  (reduce #(variant-to (if (instance? ActiveXComponent %1) (.getProperty %1 %2) (Dispatch/get %1 %2)))
    x properties))

(defmacro dispatch-get [x & properties]
  `(dispatch-on ~x ~(vec (map str properties))))


(defmacro dispatch-set [x & properties-and-key-value]
  `(let [dispatch# (dispatch-get ~x ~@(butlast properties-and-key-value))
         [k# v#] ~(last properties-and-key-value)]
    (Dispatch/put dispatch# k# v#)))

(defmacro dispatch-set-all [x & properties-and-key-values]
  `(let [dispatch# (dispatch-get ~x ~@(butlast properties-and-key-values))
         kvs# ~(last properties-and-key-values)]
    (doseq [[k# v#] (group2 kvs#)]
      (Dispatch/put dispatch# k# v#))))

(defmacro dispatch-call [x & properties-and-arguments]
  (let [properties (butlast (butlast properties-and-arguments))
        name (str (last (butlast properties-and-arguments)))
        args (last properties-and-arguments)]
  `(let [dispatch# (dispatch-get ~x ~@properties)
         name# ~name
         args# ~args]
    (variant-to (Dispatch/callN dispatch# name# (to-array args#))))))


(defmacro dispatch-fn [x & properties]
  " (def GetVariable (dispatch-fn (activex \"ShockwaveFlash.ShockwaveFlash\") GetVariable))
    (println (GetVariable \"$version\"))
  "
  `(let [dispatch# (dispatch-get ~x ~@(butlast properties))
         name# ~(str (last properties))]
    (fn [& args#] (variant-to (Dispatch/callN dispatch# name# (to-array args#))))))


(defn raw-dispatch [raw]
  (let [dispatch (Dispatch.)]
    (set! (. dispatch m_pDispatch) raw)
    dispatch))

